summaryrefslogtreecommitdiff
path: root/app/[lng]
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-11-21 09:44:33 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-11-21 09:44:33 +0000
commita2e0785c8749c4d3766ecf3b70edfb7c2fe4df20 (patch)
tree4b03bbec838baf307b38e0c5692da8da7bde2f9b /app/[lng]
parent204fbfb126daf057a4567f64cfb7ab03a5679e82 (diff)
(임수민) 준법 Red Flag 해제, 코멘트 수정
Diffstat (limited to 'app/[lng]')
-rw-r--r--app/[lng]/evcp/(evcp)/(procurement)/basic-contract/compliance-comments/[id]/page.tsx197
1 files changed, 197 insertions, 0 deletions
diff --git a/app/[lng]/evcp/(evcp)/(procurement)/basic-contract/compliance-comments/[id]/page.tsx b/app/[lng]/evcp/(evcp)/(procurement)/basic-contract/compliance-comments/[id]/page.tsx
new file mode 100644
index 00000000..359efbed
--- /dev/null
+++ b/app/[lng]/evcp/(evcp)/(procurement)/basic-contract/compliance-comments/[id]/page.tsx
@@ -0,0 +1,197 @@
+import * as React from "react";
+import { notFound } from "next/navigation";
+import Link from "next/link";
+import { eq } from "drizzle-orm";
+
+import db from "@/db/db";
+import { basicContractView } from "@/db/schema";
+import { Shell } from "@/components/shell";
+import {
+ Breadcrumb,
+ BreadcrumbList,
+ BreadcrumbItem,
+ BreadcrumbLink,
+ BreadcrumbSeparator,
+ BreadcrumbPage,
+} from "@/components/ui/breadcrumb";
+import { Card, CardHeader, CardTitle, CardDescription, CardContent } from "@/components/ui/card";
+import { Badge } from "@/components/ui/badge";
+import { Button } from "@/components/ui/button";
+import { AgreementCommentList } from "@/lib/basic-contract/agreement-comments/agreement-comment-list";
+import { formatDateTime } from "@/lib/utils";
+import { checkNegotiationStatus } from "@/lib/basic-contract/agreement-comments/actions";
+import { MessageCircle, Building2, FileText, Calendar, ArrowLeft } from "lucide-react";
+
+interface ComplianceCommentsPageProps {
+ params: Promise<{ id: string }>;
+}
+
+export const revalidate = 0;
+
+export default async function ComplianceCommentsPage(props: ComplianceCommentsPageProps) {
+ const params = await props.params;
+ const contractId = Number(params.id);
+
+ if (Number.isNaN(contractId)) {
+ notFound();
+ }
+
+ const contract = await db
+ .select()
+ .from(basicContractView)
+ .where(eq(basicContractView.id, contractId))
+ .limit(1)
+ .then((rows) => rows[0]);
+
+ if (!contract) {
+ notFound();
+ }
+
+ const negotiationSummary = await checkNegotiationStatus(contractId);
+
+ const negotiationStatusLabel = contract.negotiationCompletedAt
+ ? "협의 완료"
+ : negotiationSummary.hasComments
+ ? `협의 진행중 (${negotiationSummary.commentCount}건)`
+ : "협의 없음";
+
+ const negotiationBadgeClass = contract.negotiationCompletedAt
+ ? "bg-green-50 text-green-700 border-green-200"
+ : negotiationSummary.hasComments
+ ? "bg-orange-50 text-orange-700 border-orange-200"
+ : "bg-gray-50 text-gray-600 border-gray-200";
+
+ const templateLink = contract.templateId
+ ? `/evcp/basic-contract/${contract.templateId}`
+ : "/evcp/basic-contract";
+
+ return (
+ <Shell className="gap-4">
+ <div className="flex flex-wrap items-center justify-between gap-3">
+ <Breadcrumb>
+ <BreadcrumbList>
+ <BreadcrumbItem>
+ <BreadcrumbLink href="/evcp">EVCP</BreadcrumbLink>
+ </BreadcrumbItem>
+ <BreadcrumbSeparator />
+ <BreadcrumbItem>
+ <BreadcrumbLink href="/evcp/basic-contract">기본계약서/서약서 관리</BreadcrumbLink>
+ </BreadcrumbItem>
+ <BreadcrumbSeparator />
+ <BreadcrumbItem>
+ <BreadcrumbPage>
+ {contract.vendorName ? `${contract.vendorName} 협의 코멘트` : "협의 코멘트"}
+ </BreadcrumbPage>
+ </BreadcrumbItem>
+ </BreadcrumbList>
+ </Breadcrumb>
+
+ <Button asChild variant="outline" size="sm">
+ <Link href={templateLink}>
+ <ArrowLeft className="h-4 w-4 mr-2" />
+ 계약 상세로 돌아가기
+ </Link>
+ </Button>
+ </div>
+
+ <Card>
+ <CardHeader className="pb-3">
+ <div className="flex flex-wrap items-center justify-between gap-3">
+ <div className="space-y-1">
+ <CardTitle className="flex items-center gap-2 text-lg">
+ <FileText className="h-4 w-4 text-blue-500" />
+ {contract.templateName || "기본계약서"}
+ </CardTitle>
+ <CardDescription>
+ 계약서 ID {contract.id} · 템플릿 ID {contract.templateId ?? "-"}
+ </CardDescription>
+ </div>
+ <Badge variant="outline" className={`flex items-center gap-1 ${negotiationBadgeClass}`}>
+ <MessageCircle className="h-3 w-3" />
+ {negotiationStatusLabel}
+ </Badge>
+ </div>
+ </CardHeader>
+ <CardContent className="grid gap-4 md:grid-cols-2">
+ <div className="space-y-3">
+ <h4 className="text-sm font-semibold text-gray-700 flex items-center gap-2">
+ <Building2 className="h-4 w-4 text-gray-500" />
+ 협력업체 정보
+ </h4>
+ <div className="rounded border bg-gray-50 p-3 text-sm space-y-1">
+ <div className="flex justify-between">
+ <span className="text-gray-500">업체명</span>
+ <span className="font-medium text-gray-900">
+ {contract.vendorName || "미지정"}
+ </span>
+ </div>
+ <div className="flex justify-between">
+ <span className="text-gray-500">업체코드</span>
+ <span className="font-mono text-gray-900">
+ {contract.vendorCode || "-"}
+ </span>
+ </div>
+ <div className="flex justify-between">
+ <span className="text-gray-500">이메일</span>
+ <span className="text-gray-900">{contract.vendorEmail || "-"}</span>
+ </div>
+ </div>
+ </div>
+
+ <div className="space-y-3">
+ <h4 className="text-sm font-semibold text-gray-700 flex items-center gap-2">
+ <Calendar className="h-4 w-4 text-gray-500" />
+ 진행 정보
+ </h4>
+ <div className="rounded border bg-gray-50 p-3 text-sm space-y-1">
+ <div className="flex justify-between">
+ <span className="text-gray-500">요청일</span>
+ <span className="text-gray-900">
+ {formatDateTime(contract.createdAt, "KR")}
+ </span>
+ </div>
+ <div className="flex justify-between">
+ <span className="text-gray-500">서명 상태</span>
+ <span className="text-gray-900">
+ {contract.vendorSignedAt ? "협력업체 서명완료" : "협력업체 서명대기"}
+ </span>
+ </div>
+ <div className="flex justify-between">
+ <span className="text-gray-500">협의 완료일</span>
+ <span className="text-gray-900">
+ {contract.negotiationCompletedAt
+ ? formatDateTime(contract.negotiationCompletedAt, "KR")
+ : "-"}
+ </span>
+ </div>
+ </div>
+ </div>
+ </CardContent>
+ </Card>
+
+ <Card>
+ <CardHeader className="pb-3">
+ <div className="flex flex-wrap items-center justify-between gap-3">
+ <div>
+ <CardTitle className="text-lg">협의 코멘트</CardTitle>
+ <CardDescription>
+ {contract.vendorName
+ ? `${contract.vendorName}과(와)의 협의 내용을 기록하고 공유합니다.`
+ : "협의 코멘트를 작성하고 상대방과 공유합니다."}
+ </CardDescription>
+ </div>
+ </div>
+ </CardHeader>
+ <CardContent className="h-[620px] pt-0">
+ <AgreementCommentList
+ basicContractId={contractId}
+ currentUserType="SHI"
+ readOnly={false}
+ isNegotiationCompleted={!!contract.negotiationCompletedAt}
+ />
+ </CardContent>
+ </Card>
+ </Shell>
+ );
+}
+